/*
 * @(#)XfvhdlAntecedentMemFiles.java        3.0              2004/09/14
 *
 * This file is part of Xfuzzy 3.0, a design environment for fuzzy logic
 * based systems.
 *
 * (c) 2000 IMSE-CNM. The authors may be contacted by the email address:
 *                    xfuzzy-team@imse.cnm.es
 *
 * Xfuzzy is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 *
 * Xfuzzy is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 */

package xfuzzy.xfvhdl;

import xfuzzy.*;
import xfuzzy.lang.*;

/**
* Clase que genera los ficheros de las memorias de antecedentes 
* AntecedentMem_x.vhdl.
* @author Jos� Mar�a �vila Maireles, <b>e-mail</b>: josavimai@alum.us.es
* @version 3.0
*/
public class XfvhdlAntecedentMemFiles {

   // El siguiente atributo se usa para crear el archivo .prj
   private XfvhdlPrjFile prjFile;
   // El siguiente atributo se usa para mostrar los mensajes por pantalla. 
   private XfvhdlMessage msg;

   //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
   //			  CONSTRUCTOR DE LA CLASE				          
   //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//

   /** Constructor de la clase.
    */
   XfvhdlAntecedentMemFiles(XfvhdlPrjFile pF, Xfuzzy xf) {
      prjFile = pF;
      msg = new XfvhdlMessage(xf);
   }

   //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
   //			  M�TO_DOS P�BLICOS DE LA CLASE				      
   //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
   /**
   * M�todo que genera los fichero de antecedentes de memoria 
   * (AntecedentMem.vhdl).
   */
   public void createAntecedentsMemory(Specification spec) {
      // Las 2 siguientes l�neas han sido reemplazadas porque te 
      // generaban la memoria de antecedentes de las salidas, y eso 
      // no es necesario. 
      // OJO, el nombre del fichero tambi�n se ha modificado. Ahora se 
      // incrementa en 1 para que no empiece en 0.
      // Tambi�n se ha cambiado la llamada a la funci�n que crea el 
      // fichero.

      //int actual=1;
      //Variable [] var = spec.getSystemModule().getVariables();
      int actual = 0;
      Variable[] var = spec.getSystemModule().getInputs();
      int total = var.length;
      XfvhdlUniverse u = new XfvhdlUniverse();
      XfvhdlDiscretizeUniverse disc = new XfvhdlDiscretizeUniverse();
      String state = new String("Done");
      XfvhdlError error = new XfvhdlError();

      // Para todas las variables (*******incluidas las INNER***********)
      while (actual < total) {
         // Discretizo el universo de discurso para la variable actual
         u = disc.discretizeUniverse(var[actual]);

         msg.addMessage(
            "\n>>>> Generating file:  "
               + XfvhdlProperties.outputFile
               + "AntecedentMem_"
               + (actual + 1)
               + ".vhdl");
         msg.show();
         // Creo el fichero Antecedent_Mem_actual.vhdl.
         new XfvhdlCreateFile(
            XfvhdlProperties.outputFile
               + "AntecedentMem_"
               + (actual + 1)
               + ".vhdl",
            createMemorySource(var, actual + 1, u));
         prjFile.addFile(
            XfvhdlProperties.outputFile
               + "AntecedentMem_"
               + (actual + 1)
               + ".vhdl");

         if (error.hasErrors())
            state = "With error";
         if (XfvhdlProperties.complementaryFiles == true) {
            msg.addMessage(
               "  (with complementary files)     ......... " + state);
            msg.show();
         } else {
            msg.addMessage("     ......... " + state);
            msg.show();
         }

         actual++;
      }
   }

   //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
   //			  M�TO_DOS PRIVADOS DE LA CLASE				        
   //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//

   /**
   * M�todo que crea la cadena que ser� escrita en fichero 
   * AntecedentMem.vhdl.
   * @return Devuelve la cadena que ser� escrita en fichero 
   * AntecedentMem.vhdl.
   */
   private String createMemorySource(
      Variable[] var,
      int actual,
      XfvhdlUniverse u) {

      XfvhdlHeadFile head =
         new XfvhdlHeadFile(
            XfvhdlProperties.fileDir,
            XfvhdlProperties.outputFile
               + "AntecedentMem_"
               + (actual)
               + ".vhdl",
            XfvhdlProperties.ficheroXFL);

      String code = head.getHead();

      code
         += "\n--***********************************************************************--\n"
         + "--                                                                       --\n"
         + "--   DESCRIPTION: This file contains the VHDL description for the        --\n"
         + "--                antecedent memory of the fuzzy controller.             --\n"
         + "--                                                                       --\n"
         + "---------------------------------------------------------------------------\n"
         + "--                                                                       --\n"
         + "--   AUTHOR:      Jose Maria Avila Maireles                              --\n"
         + "--                                                                       --\n"
         + "--   VERSION:     Xfvhdl  ver0.1                          October 2003   --\n"
         + "--                                                                       --\n"
         + "--***********************************************************************--\n"
         + "\n"
         + "\n"
         + "\n"
         + "library IEEE;\n"
         + "use IEEE.std_logic_1164.all;\n"
         + "use IEEE.std_logic_unsigned.all;\n"
         + "\n"
         + "use WORK.Constants.all;\n"
         + "\n"
         + "\n"
         + "---------------------------------------------------------------------------\n"
         + "--                           Entity description                          --\n"
         + "---------------------------------------------------------------------------\n"
         + "\n"
         + "entity AntecedentMem_"
         + actual
         + " is\t\t\t\t-- Antecedent memory for\n"

         // OJO: var[actual-1] se cambi� por el problema de que se creaba 
         // fichero para la salida. 
         + "\t\t\t\t\t\t\t\t-- '" + var[actual - 1].getName()
         + "' linguistic variable\n"
         + "\n"
         + "\tport(\taddr\t: in std_logic_vector(N-1 downto 0);"
         + "\t-- Address bus\n"
         + "\t\tme\t: in std_logic;"
         + "\t\t\t\t\t-- Memory enable\n"
         + "\n"
         + "\t\tdo\t: out std_logic_vector(M-1 downto 0));"
         + "\t-- Data bus\n"
         + "end AntecedentMem_"
         + actual
         + ";\n"
         + "\n"
         + "\n"
         + "---------------------------------------------------------------------------\n"
         + "--                       Architecture description                        --\n"
         + "---------------------------------------------------------------------------\n"
         + "\n"
         + "architecture FPGA of AntecedentMem_"
         + actual
         + " is\n"
         + "\n"
         + "\tsubtype ROM_WORD is std_logic_vector(M-1 downto 0);\n"
         + "\ttype ROM_TABLE is array (0 to fil-1) of ROM_WORD;\n"
         + "\tconstant ROM: ROM_TABLE := ROM_TABLE'(\n";

      XfvhdlBinaryDecimal converter = new XfvhdlBinaryDecimal();
      String val1 = new String();
      String val2 = new String();

      for (int i = 0; i < u.getLength() - 1; i++) {
         val1 =
            converter.toBinaryInRange(
               u.getXUniversePoint(i).getVal1(),
               0.0,
               1.0,
               XfvhdlProperties.grad);
         val2 =
            converter.toBinaryInRange(
               u.getXUniversePoint(i).getVal2(),
               0.0,
               1.0,
               XfvhdlProperties.grad);

         code += "\t\t\tROM_WORD'(\""
            + converter.toBinary(
               (u.getXUniversePoint(i).getEtiq()) - 1,
               XfvhdlProperties.bits_etiq)
            + val1
            + val2
            + "\"),\n";
      }

      // La �ltima l�nea es especial porque hay que ponerle un 
      // parentesis al final.
      val1 =
         converter.toBinaryInRange(
            u.getXUniversePoint(u.getLength() - 1).getVal1(),
            0.0,
            1.0,
            XfvhdlProperties.grad);
      val2 =
         converter.toBinaryInRange(
            u.getXUniversePoint(u.getLength() - 1).getVal2(),
            0.0,
            1.0,
            XfvhdlProperties.grad);
      code += "\t\t\tROM_WORD'(\""
         + converter.toBinary(
            (u.getXUniversePoint(u.getLength() - 1).getEtiq()) - 1,
            XfvhdlProperties.bits_etiq)
         + val1
         + val2
         + "\"));\n";

      code += "\tbegin\n"
         + "\n"
         + "\t\tdo <= ROM(conv_integer(addr));\n\n"
         + "end FPGA;";

      return code;
   }

} // Fin de la clase
